package io.gitee.twoke.generator.engine.impl.metadata.impl;

import io.gitee.twoke.generator.engine.impl.AbstractQuery;
import io.gitee.twoke.generator.engine.impl.Page;
import io.gitee.twoke.generator.engine.impl.db.DbSqlSession;
import io.gitee.twoke.generator.engine.impl.interceptor.CommandContext;
import io.gitee.twoke.generator.engine.impl.interceptor.CommandExecutor;
import io.gitee.twoke.generator.engine.impl.metadata.Table;
import io.gitee.twoke.generator.engine.impl.metadata.TableQuery;
import cn.hutool.core.util.StrUtil;
import org.apache.ibatis.session.SqlSession;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class TableQueryImpl extends AbstractQuery<TableQuery, Table> implements TableQuery {

    Predicate<Table> predicate;
    String tableName;

    public TableQueryImpl() {
    }

    public TableQueryImpl(CommandContext commandContext) {
        super(commandContext);
    }

    public TableQueryImpl(CommandContext commandContext, String databaseType) {
        super(commandContext);
        this.databaseType = databaseType;
    }

    public TableQueryImpl(CommandExecutor commandExecutor) {
        super(commandExecutor);
    }

    public TableQueryImpl(CommandExecutor commandExecutor, String databaseType) {
        super(commandExecutor);
        this.databaseType = databaseType;
    }

    @Override
    public long executeCount(CommandContext commandContext) {
        return executeList(commandContext, null).size();
    }

    @Override
    public List<Table> executeList(CommandContext commandContext, Page page) {
        checkQueryOk();
        List<Table> allTables = null;
        try {
            allTables = findAllTables(commandContext);
        }catch (SQLException e) {
            e.printStackTrace();
        }
        if (Objects.nonNull(predicate) && Objects.nonNull(allTables)) {
            allTables = allTables.stream().filter(predicate).collect(Collectors.toList());
            if (Objects.isNull(page)) {
              return allTables;
            }
            int toIndex = (page.getFirstResult() + 1) * page.getMaxResults();
            int fromIndex = page.getFirstResult() * page.getMaxResults();
            return allTables.subList(fromIndex, toIndex < allTables.size() ? toIndex : allTables.size());
        }

        return Optional.ofNullable(allTables).orElse(new ArrayList<>());
    }


    private List<Table> findAllTables(CommandContext commandContext) throws SQLException {
        SqlSession sqlSession = commandContext.getDbSqlSession().getSqlSession();
        Connection connection = sqlSession.getConnection();
        DatabaseMetaData metaData = connection.getMetaData();
        ResultSet tables = metaData.getTables(connection
                .getCatalog(), connection.getSchema(), StrUtil.isBlank(tableName) ? null : tableName, new String[]{"TABLE"});
        List<Table> tableMetaDataList = new ArrayList<>();
        while (tables.next()) {
            // 获取表的创建时间和最后更新时间
            tableMetaDataList.add(TableImpl.builder()
                    .name(tables.getString("TABLE_NAME"))
                    .comment(tables.getString("REMARKS"))
                    .build());
        }
        return tableMetaDataList;
    }


    @Override
    public TableQuery filter(Predicate<Table> predicate) {
        if (Objects.isNull(predicate)) {
            throw new IllegalArgumentException("'predicate' must not be null");
        }
        this.predicate = predicate;
        return this;
    }

    @Override
    public TableQuery tableName(String tableName) {
        this.tableName = tableName;
        return this;
    }
}
